package cn.lirenyi.user.service.impl;

import cn.lirenyi.basic.exception.BusinessException;
import cn.lirenyi.basic.service.impl.BaseServiceImpl;
import cn.lirenyi.basic.util.AjaxResult;
import cn.lirenyi.basic.util.HttpClientUtils;
import cn.lirenyi.basic.util.MD5Utils;
import cn.lirenyi.basic.util.StrUtils;
import cn.lirenyi.user.Dto.LoginDto;
import cn.lirenyi.user.constant.UserConstant;
import cn.lirenyi.user.domain.BinderDto;
import cn.lirenyi.user.domain.Logininfo;
import cn.lirenyi.user.domain.User;
import cn.lirenyi.user.domain.WxUser;
import cn.lirenyi.user.mapper.LogininfoMapper;
import cn.lirenyi.user.mapper.UserMapper;
import cn.lirenyi.user.mapper.WxUserMapper;
import cn.lirenyi.user.service.ILogininfoService;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class LogininfoServiceImpl extends BaseServiceImpl<Logininfo> implements ILogininfoService {

    @Autowired
    private LogininfoMapper logininfoMapper;
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private WxUserMapper wxUserMapper;

    @Autowired
    private UserMapper userMapper;

    /*
        servi业务逻辑：
            1.参数不能为空
            2.查询数据（username+type）
            2.1查不到就报错
            3.校验密码
            3.1比对不成功就保存（保存redis对象时候需要序列化）
            3.2比对成功就登录成功并且保存redis
            3.3返回token+logininfo（返回的时候把盐值和密码置空）
	*/
    @Override
    public Map<String,Object> loginAcount(LoginDto loginDto) {
        // 参数不能为空
        if (StringUtils.isEmpty(loginDto.getPassword()) ||
            StringUtils.isEmpty(loginDto.getUsername()) ||
            StringUtils.isEmpty(loginDto.getType())){

            throw new BusinessException("用户名或密码错误，请重新输入1");
        }
        // 查询数据
        Logininfo logininfo = logininfoMapper.queryLoginAcount(loginDto);
        // 如果没查询到说明数据库没有，返回错误信息
        if (logininfo == null){
            throw new BusinessException("用户名或密码错误，请重新输入2");
        }
        // 校验密码，获取数据库的密码和获取传来数据的密码比较,注意加上盐值
        // 数据库的盐值和密码
        String logininfoPassword = logininfo.getPassword();
        String logininfoSalt = logininfo.getSalt();
        // 传来的密码
        String loginDtoPassword = loginDto.getPassword();
        // 密码不一样就报错（保存redis对象时候需要序列化）
        if(!logininfoPassword.equals(MD5Utils.encrypByMd5(loginDtoPassword+logininfoSalt))){
            throw new BusinessException("用户名或密码错误，请重新输入3");
        }
        // 获取uuid
        String token = UUID.randomUUID().toString();
        // 把token保存在redis并且设置30分钟有效期
        redisTemplate.opsForValue().set(token,logininfo,30,TimeUnit.MINUTES);

        Map<String,Object> map = new HashMap<>();
        map.put("token", token);
        logininfo.setSalt(null);
        logininfo.setPassword(null);
        map.put("loginInfo", logininfo);
        return map;

    }

    @Override
    public AjaxResult wechat(Map<String, String> params) {
        // 空校验，判断params参数里面的code不能为空
        String code = params.get("code");
        if (StringUtils.isEmpty(code)){
            throw new BusinessException("没有授权码");
        }
        // 根据code从微信获取token,官网里面有如何获取token
        String getTokenUrl = UserConstant.WXUSER_GET_TOKEN_URL
                // 同名更换
                .replace("APPID", UserConstant.APPID)
                .replace("SECRET", UserConstant.SECRET)
                .replace("CODE", code);

        // 获取token
        String httpGet = HttpClientUtils.httpGet(getTokenUrl);
        /*if (StringUtils.isEmpty(httpGet)){
            throw new BusinessException("没有该用户");
        }*/
        // albb提供的包转换成json对象方法
        JSONObject parseObject = JSONObject.parseObject(httpGet);
        // 获取json里面需要的参数
        // 令牌
        String accessToken = parseObject.getString("access_token");
        // 微信号
        String openId = parseObject.getString("openid");
        // 根据微信号查询是否有该用户
        WxUser wxUser = wxUserMapper.loadByOpenId(openId);
        // 判断该用户是否已经绑定过，用于区分是绑定还是免密登录

        // =============================免密登录分割线===========================
        if (wxUser != null && wxUser.getUser_id() != null){
            Logininfo logininfo = logininfoMapper.queryByUserId(wxUser.getUser_id());
            // 获取uuid
            String token = UUID.randomUUID().toString();
            // 把token保存在redis并且设置30分钟有效期
            redisTemplate.opsForValue().set(token,logininfo,30,TimeUnit.MINUTES);

            Map<String,Object> map = new HashMap<>();
            map.put("token", token);
            logininfo.setSalt(null);
            logininfo.setPassword(null);
            map.put("loginInfo", logininfo);
            return AjaxResult.me().setResultObj(map);
        }
        // =============================免密登录分割线==========================
        // 如果用户未绑定过，说明是第一次的用户，应该跳转到绑定页面并且返回token和openid
        String binderUrlParams = "?accessToken="+accessToken+"&openId="+openId;
        return AjaxResult.me().setSuccess(false).setResultObj(binderUrlParams);
    }

    @Override
    public Map<String,Object> binder(BinderDto binderDto) {
        String accessToken = binderDto.getAccessToken();
        String openId = binderDto.getOpenId();
        String phone = binderDto.getPhone();
        String verifyCode = binderDto.getVerifyCode();
        if (StringUtils.isEmpty(accessToken) || StringUtils.isEmpty(openId) ||
                StringUtils.isEmpty(phone) || StringUtils.isEmpty(verifyCode)){
            throw new BusinessException("请输入绑定信息");
        }
        // 判断验证码是否过期
        Object codeObj = redisTemplate.opsForValue().get(UserConstant.BUSINESS_BINDER_PREFIX + phone);
        if (codeObj == null){
            throw new BusinessException("该验证码已过期，请重新获取");
        }
        // 验证码是否相等	注意不要区分大小写
        String code = ((String)codeObj).split(":")[0];
        if (!code.equalsIgnoreCase(verifyCode)){
            throw new BusinessException("请输入正确验证码");
        }
        // 查询手机不能被注册
        User userTmp = userMapper.queryByPhone(phone);
        User user = null;
        Logininfo loginInfo = null;
        if(userTmp != null){
            // 曾经已经注册过了，可以直接绑定微信用户
            user = userTmp;
            loginInfo = logininfoMapper.queryById(user.getLogininfo_id());
        }else{  // 没有用户，需要创建平台用户
            user = initUser(phone);
            loginInfo = user2LoginInfo(user);
            logininfoMapper.add(loginInfo);
            user.setLogininfo_id(loginInfo.getId());
            userMapper.add(user);
        }
        // 通过token+openId 获取微信用户信息
        String getUserUrl = UserConstant.WXUSER_GET_USER_URL
                .replace("ACCESS_TOKEN", accessToken)
                .replace("OPENID", openId);
        String wxUserTmp = HttpClientUtils.httpGet(getUserUrl);
        // 生成wxuser信息并绑定平台用户
        WxUser wxUser = initWxUser(wxUserTmp,user);
        wxUserMapper.add(wxUser);
        // 免密登录
        // 直接扫码登录  免密登录
        // 登录成功保存redis  token
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(
                token,
                loginInfo,
                30,
                TimeUnit.MINUTES);
        // 返回token + loginInfo
        Map<String,Object> map = new HashMap<>();
        map.put("token", token);
        // 制空敏感信息
        loginInfo.setSalt(null);
        loginInfo.setPassword(null);
        map.put("loginInfo", loginInfo);
        return map;
    }

    private WxUser initWxUser(String wxUserTmp, User user) {
        //装换微信用户信息
        JSONObject jsonObject = JSONObject.parseObject(wxUserTmp);
        WxUser wxUser =  new WxUser();
        wxUser.setUser_id(user.getId());//绑定用户
        wxUser.setOpenid(jsonObject.getString("openid"));
        wxUser.setNickname(jsonObject.getString("nickname"));
        wxUser.setSex(jsonObject.getInteger("sex"));
        wxUser.setAddress(null);
        wxUser.setHeadimgurl(jsonObject.getString("headimgurl"));
        wxUser.setUnionid(jsonObject.getString("unionid"));
        return wxUser;
    }

    private Logininfo user2LoginInfo(User user) {
        Logininfo loginInfo = new Logininfo();
        BeanUtils.copyProperties(user, loginInfo);
        loginInfo.setType(1);
        return loginInfo;
    }

    private User initUser(String phone) {
        User user = new User();
        user.setUsername(phone);
        user.setPhone(phone);
        // 盐值
        String salt = StrUtils.getComplexRandomString(32);
        // 使用盐值加密之后的密码 生成随机密码并发短信通知用户
        String md5Pwd = MD5Utils.encrypByMd5("1" + salt);
        user.setSalt(salt);
        user.setPassword(md5Pwd);
        return user;
    }

}

